iT邦幫忙

2026 iThome 鐵人賽

DAY 1
0
Software Development

異步程式設計修煉:Kotlin Coroutines 完全指南系列 第 1

Day 00:異步程式設計修煉:Kotlin Coroutines 完全指南

  • 分享至 

  • xImage
  •  

你大概寫過這樣的程式碼。一個 viewModelScope.launch 包住一段網路請求,一個 async 搭配 awaitAll 平行抓了好幾筆資料,跑起來一切正常,畫面該更新的時候更新,該轉圈圈的時候轉圈圈。你把這段程式碼複製貼上到下一個專案,改幾個變數名稱,一樣能動。久而久之你也習慣了這種寫法,覺得自己已經會用協程了。

真正的裂縫,通常出現在一次意外的 debug 現場。可能是某個協程明明呼叫了取消,畫面卻還是在跑;可能是某個 try-catch 包住了整個 launch,例外卻像穿牆一樣直接讓 App 當掉;也可能只是主管隨口問了一句,這個 suspend function 執行到一半跑去哪裡了,你張口卻答不出來。你開始意識到,自己會的其實是「照著範例改寫」,而不是「理解協程在做什麼」。這兩件事表面上看起來很像,實際上是完全不同量級的能力,前者讓程式碼能動,後者讓你在程式碼出問題的當下,知道問題可能出在哪裡。

這正是想要撰寫這個系列的理由。

這個系列要帶你建立的能力

這個系列不是一份 Kotlin 協程 API 的中文翻譯導讀,市面上這類文件不缺,缺的是把這些 API 串起來的那條時間軸。核心目標只有一個,讓你看到一段協程程式碼時,能在腦中還原出它的執行順序,知道它何時暫停、何時恢復、暫停時這個協程的狀態被誰持有、又是在什麼條件下會被取消。具備這種能力之後,launchasync 不再是兩個要背起來的關鍵字,而是你能推導出彼此差異的兩種行為模式。

目標讀者是已經在專案裡用過協程,但沒有系統化的學過它底層在做什麼的工程師。你可能是 Android 工程師,也可能是用 Ktor 寫後端服務,或是嘗試 Kotlin Multiplatform,KMP,跨平台開發,甚至只是單純想把 Kotlin 當成主力語言深耕。這個系列不預設你正在用哪一種應用框架,唯一的門檻是你看得懂 Lambda、擴充函式、高階函式這些 Kotlin 基礎語法。如果你完全沒寫過 Kotlin,這個系列會有點吃力,建議先把語法基礎打穩再回來。

這裡要特別說明一件事避免讀者混淆。另一個系列「Spring Boot 3 + Kotlin 協程高併發,後端開發新選擇」也會談協程,但那個系列的立場是拿協程去解決 Spring Boot 後端在高併發場景下的實務問題,情境綁定在訂單查詢與扣庫存這類後端服務上。這個系列完全不同,聚焦的是協程這套語言機制本身,不綁任何後端框架,也不預設你在寫後端。如果你是 Android 工程師或 KMP 開發者,那個系列對你幫助有限,這個系列才是你該從頭讀起的起點。反過來說,如果你已經是 Spring Boot 後端工程師,把這個系列當成地基,再去讀那個系列會走得更穩,因為那個系列會直接假設你已經具備這裡建立的心智模型。

這個系列採「暫停的秘密 > 結構化並發地基 > 執行環境與例外治理 > Flow 資料流 > 測試與實戰整合」的五段式弧線,前兩階段刻意放慢腳步,用 11 天把 suspend function 的底層原理與結構化並發的規則打穩。市面上不少協程教學急著在第三、四天就跳進 Flow,讀者往往似懂非懂地硬套用法,卻答不出來 Flow 底下的協程到底何時被取消。這個系列反其道而行,先把地基做扎實,後面的內容才站得住腳。

一個會慢慢長大的示範情境

全系列共用一條輕量、跨平台皆適用的示範情境,一個多來源圖片下載與聚合工具。第一天它只是一個會卡住主執行緒的單一下載函式,簡陋到幾乎不值得稱作工具。隨著系列推進,結構化並發、取消機制、例外處理這些觀念陸續建立起來,它會陸續長出多來源平行下載、逾時控制、失敗重試這些真實情境會遇到的複雜度,到了 Flow 階段,它會收斂成一個能持續回報下載進度的資料流。到系列後段,這個工具會有一個正式的名字,圖片下載工具完整版,並在測試與實戰整合期補齊單元測試,附上簡短的跨平台示範,看看同一套協程邏輯在 Android 與 Ktor 上分別怎麼用。

你不需要每天都回頭補完整個專案,每天用到的只是整體工具的一個切片,讀完當天內容不會卡關。但如果你跟著系列一路讀下來,會明顯感覺到這個工具的異步控制能力一天比一天完整,這種累積感,正是我們刻意設計的,因為協程的價值往往要在情境變複雜之後才真正顯現出來,一個永遠只下載一張圖片的範例,是看不出結構化並發為什麼重要的。

30 天完整地圖

以下依五個階段分組呈現整個系列的全貌。每個階段標題下方先說明這個階段要讓你建立起什麼樣的能力,再列出該階段每一天的標題與一句話定位。閱讀當下不需要理解每一天的技術細節,只需要對整體節奏有個印象,等你實際走到某一天,回來這裡對照一下自己的位置即可。

階段一:暫停的秘密,Day 1 - Day 5

五天,目標是建立協程存在的動機,拆解 suspend function 與 Continuation 的底層機制,學會三種 Coroutine Builder 的差異與選用時機。

  • 《Day 01:為什麼你需要協程,從一個會卡住主執行緒的下載函式說起》,建立協程存在的動機,定案示範情境:多來源圖片下載與聚合工具,定案 Callback Hell 與既有異步手段的極限錨點
  • 《Day 02:第一個 suspend function,暫停到底暫停了什麼》,定案 suspend function 錨點,建立協程「暫停不等於阻塞」的心智模型
  • 《Day 03:Continuation 是什麼,編譯器在背後偷偷做了什麼事》,定案 Continuation 錨點,拆解 Continuation-Passing Style 的轉換概念
  • 《Day 04:launch、async、runBlocking,三種 Coroutine Builder 該選誰》,定案 Coroutine Builder 錨點,釐清三者的回傳值、阻塞行為與適用情境差異
  • 《Day 05:小結:把暫停機制與啟動方式放在一起跑一次》,整合前四天內容,用同一個情境對照三種啟動方式的行為差異,緩衝日

階段二:結構化並發地基,Day 6 - Day 11

六天,目標是建立 Coroutine Scope、Structured Concurrency、Job、取消機制這幾個貫穿全系列的核心心智模型。

  • 《Day 06:Coroutine Scope,協程住在哪裡、活多久》,定案 Coroutine Scope 錨點,建立協程生命週期容器的概念
  • 《Day 07:Structured Concurrency,為什麼協程不能亂長亂放》,定案 Structured Concurrency 錨點,解釋父子協程的收斂規則
  • 《Day 08:coroutineScope 與 supervisorScope,兩種收斂行為的差異》,對照兩種內建 Scope 建構函式,示範失敗時是否向上傳播
  • 《Day 09:Job,協程生命週期的控制把手》,定案 Job 錨點,講清楚 Job 如何表達狀態與建立父子關係
  • 《Day 10:協程取消不是強制中斷,是一場合作》,定案協程取消機制,Cooperative Cancellation,錨點,示範可取消點與不可取消的常見誤區
  • 《Day 11:小結:Scope、Structured Concurrency、Job、取消如何協同運作》,整合 Coroutine Scope、Structured Concurrency、Job、取消機制四個錨點,緩衝日

階段三:執行環境與例外治理,Day 12 - Day 18

七天,目標是掌握協程實際跑在哪、上下文如何組成、例外如何傳播與隔離,建立生產等級的錯誤處理習慣。

  • 《Day 12:Dispatchers,協程實際跑在哪條執行緒上》,定案 Dispatchers 錨點,區分 Default、IO、Main、Unconfined 的適用情境
  • 《Day 13:Coroutine Context,協程隨身攜帶的那包設定》,定案 Coroutine Context 錨點,講清楚 Context 元素如何組合與覆寫
  • 《Day 14:withContext 切換執行緒,你以為的暫停其實是搬家》,示範 withContext 如何在同一個協程內切換 Dispatcher,對照 Day 12 的錨點
  • 《Day 15:一個協程失敗,其他協程要不要一起死,SupervisorJob 登場》,定案 SupervisorJob 與例外隔離錨點,承接 Day 8 的兩種 Scope 對照
  • 《Day 16:CoroutineExceptionHandler,例外最後會被誰接住》,定案 CoroutineExceptionHandler 錨點,釐清例外傳播路徑與攔截時機
  • 《Day 17:try-catch 在協程裡為什麼有時候沒用》,用示範情境的多來源下載失敗案例,示範常見的例外處理誤區
  • 《Day 18:小結:協程的執行環境與例外治理工具箱總覽》,回顧本階段所有機制,預告即將進入 Flow 資料流,關鍵轉折日

階段四:Flow 資料流,Day 19 - Day 25

七天,目標是理解 Flow 為何存在、如何操作與組合,並掌握 StateFlow、SharedFlow、Channel、背壓這些進階資料流控制手段。

  • 《Day 19:從回傳一個值到回傳一串值,Flow 是什麼》,定案 Flow 錨點,建立冷流、依序發送、可取消這三個核心特性的心智模型
  • 《Day 20:Flow 的操作符,map、filter、collect 這些常用招式》,示範 Flow 操作符如何組合成資料處理管線,對照示範情境的下載進度串流
  • 《Day 21:StateFlow 與 SharedFlow,冷流不夠用的時候》,定案 StateFlow 與 SharedFlow 錨點,釐清熱流與冷流的差異與各自的適用情境
  • 《Day 22:Channel,協程之間怎麼傳話》,定案 Channel 錨點,示範發送端與接收端的基本操作
  • 《Day 23:Flow 底層其實是 Channel,兩者的關係是什麼》,承接 Day 19 與 Day 22,說明 Flow 與 Channel 的實作關係與各自獨立使用的時機
  • 《Day 24:背壓是什麼,生產太快時該怎麼踩煞車》,定案背壓錨點,用 Flow 或 Channel 示範速度不對等的因應策略
  • 《Day 25:小結:Flow 資料流工具箱總覽,準備進測試與收斂期》,回顧本階段所有資料流控制手段,預告測試與實戰整合期,緩衝日

階段五:測試、陷阱與實戰整合,Day 26 - Day 30

五天,目標是學會用官方測試框架驗證協程行為,盤點常見陷阱與最佳實踐,收斂進一個具名示範專案並完賽總結。

  • 《Day 26:幫協程寫測試,runTest 與虛擬時間排程器》,定案 TestCoroutineScheduler 與 runTest 錨點,示範如何在測試中控制協程時間
  • 《Day 27:收斂進一個具名專案,圖片下載工具完整版,順便看看 Android 與 Ktor 怎麼用》,定案示範專案錨點,把前四階段觀念收斂進具名專案,並附上簡短跨平台示範
  • 《Day 28:協程常見陷阱總盤點,這些坑我們都踩過》,盤點 GlobalScope 濫用、忘記結構化、例外吞噬等常見錯誤與對應正確寫法
  • 《Day 29:全系列整合驗收,跑一次完整的多來源下載情境》,端到端驗證示範專案在真實多來源下載情境下的完整行為
  • 《Day 30:完賽總結,協程解決了什麼、又留下什麼取捨》,呼應 Day 1 的動機,誠實檢討協程模型的限制,系列收尾

小結:這套地圖存在的意義

30 天的天數配置刻意不均分,這是一套有意識設計的難度曲線。前兩階段用 11 天把暫停機制與結構化並發的地基打穩,看起來進度慢,實際上是為了避免你在還不理解 Structured Concurrency 之前就被丟進 Flow、Channel 這些建立在協程之上的進階抽象,導致似懂非懂地硬套用法,遇到問題時卻找不到根源。執行環境與例外治理階段給了七天,是因為 Dispatchers、Context、例外傳播這些內容一旦沒學紮實,會直接反映在正式環境的錯誤處理品質上。

回到文章開頭那個讓你答不出來的瞬間,某個協程明明取消了卻還在跑,某個例外像穿牆一樣繞過了你的 try-catch。這些現象不是巧合,也不是協程設計得不好,而是背後有一套明確的規則在運作,只是你還沒看過那條時間軸。這 30 天要做的,就是把這條時間軸攤開來給你看清楚,讓你下次遇到類似狀況時,能靠推理而不是靠猜測找到問題所在。

明天我們將正式進入 《Day 01:為什麼你需要協程,從一個會卡住主執行緒的下載函式說起》,從那個會卡住主執行緒的下載函式開始,把協程存在的理由攤開來看清楚。


下一篇
Day 01:為什麼你需要協程,從一個會卡住主執行緒的下載函式說起
系列文
異步程式設計修煉:Kotlin Coroutines 完全指南4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言